Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » [Tutoriel] L'aléatoire en C/C++
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

[Tutoriel] L'aléatoire en C/C++

Posté le 25/02/2014 18:17

Besoin d'un peu d'aléatoire dans tes programmes C/C++ ? Ce tuto est fait pour toi !


Prérequis :

Tout d'abord, la génération de nombres aléatoires de manière "classique" en C/C++ repose sur les fonctions rand() et srand(). Celles-ci sont incluses dans la bibliothèque stdlib.h, il sera donc nécessaire de l'inclure dans le header de notre projet.


Générer des nombres aléatoires :

Pour générer un nombre aléatoire, le microprocesseur est incapable d'en déterminer un lui même. Il faut l'aider un peu, et c'est ce que l'on a fait en rentrant dans la calculatrice une fonction de ce type :

static unsigned int lastrandom=0x12345678;

unsigned int random(int seed = 0)
{
        if(seed) lastrandom = seed;
        lastrandom = ( 0x41C64E6D * lastrandom ) + 0x3039;
        return (lastrandom >> 16);
}


Bref, lors de son premier appel, la fonction rand() retournera alors le nombre de seed 0, puis celui dont le seed est la dernière valeur générée. On aura donc, par exemple
-> 0x 52 07 EB F8
-> 0x 72 65 C8 62
-> Etc.

Le problème, c'est que du coup, à chaque lancement du programme on aura les mêmes valeurs, puisque le seed original est le même...

Pour palier à cela, on détermine plus ou moins aléatoirement le seed avant le premier appel de la fonction avec srand(int position). On ne l'utilisera qu'une seule fois, au tout début du programme.

Le plus dur dans tout ça, c'est de trouver un nombre qui soit suffisamment "aléatoire" pour qu'il soit différent à chaque fois. Pour cela, nous allons utiliser le syscall RTC_getTicks().

RTC_getTicks() est une fonction très pratique qui retourne le nombre de ticks, c'est à dire de fractions (1/128) de seconde qui se sont écoulés depuis une certaine date (inconnue). Autant dire que la probabilité que le programme soit lancé deux fois en 1/128 seconde est minimale.

Voici le code à inclure :
static int SysCallCode[] = {0xD201422B,0x60F20000,0x80010070};
static int (*SysCall)(int R4, int R5, int R6, int R7, int FNo ) = (void*)&SysCallCode;

int RTC_getTicks()
{
     return (*SysCall)(0, 0, 0, 0, 0x3B);
}


Pour résumer, générer un nombre aléatoire se fait de cette façon :
1) On initialise avec srand(RTC_getTicks());
2) On récupère le nombre avec rand() : int nbAlea = rand();


Traitement du nombre aléatoire :

C'est bien joli, mais rand() ne retourne qu'un nombre compris entre 0 et 2^32-1 = 4294967295. Et nous voudrions un nombre entier entre 0 et 10, par exemple. C'est pour cela que nous allons modifier ce nombre :

Nombre entier entre 0 et max :
Nous allons utiliser le modulo (%), opération très pratique qui retourne le résultat de la division euclidienne de a par b (a%b). Or, puisque que ce reste n'est jamais supérieur à b, il est forcément égal à 0, 1, 2, 3, ..., b-1. Nous pouvons donc faire, pour générer un nombre entre 0 (inclus) et max (exclus) :
int rand_int(int max)
{
    return rand() % max;
}


Nombre entier entre min et max :
Toujours en utilisant le modulo, il est possible de bidouiller la fonction ci-dessus pour inclure le fait d'avoir un minimum :
int rand_int_ab(int min, int max)
{
    return rand() % (max - min) + min;
}

On a donc un nombre entier aléatoire entre min (inclus) et max (exclus).

Nombre décimal entre min et max :
Le problème du modulo, c'est qu'il ne permet que de travailler sur des entiers. Nous allons donc devoir nous en passer pour la génération de nombre décimaux (sous forme de float).
Nous avons vu que rand() retournait un nombre entre 0 et 2^32. Donc en supposant que RAND_MAX = 2^32, rand() / RAND_MAX est compris entre 0 et 1. Sachant que RAND_MAX est déjà défini dans "time.h", on peut l'utiliser tel quel. On en déduit alors la fonction suivante :
float rand_float_ab(float min, float max)
{
    return ( rand() / RAND_MAX ) * (max - min) + min;
}



Conclusion et annexes :

Ce tuto touche à son terme, j'espère qu'il t'aura été utile, et que tu as compris les bases de la fonction rand().
Si toutefois tu souhaite plus d'informations, ou que tu as une question, n'hésite-pas à laisser un commentaire ci-dessous !

De plus, tu trouvera peut-être ton bonheur sur l'ancien Site du Zéro, et plus particulièrement ici.


A bientôt sur Planète Casio !


Louloux Hors ligne Ancien administrateur Points: 7035 Défis: 61 Message

Citer : Posté le 03/03/2014 10:42 | #


Btl a écrit :
Je pense que Louloux a l'habitude d'utiliser le nombre de frames écoulées depuis le lancement de l'add-ins.
(Il l'avait dit quelque part)

Désolé de vous décevoir, mais dans Mipjabok je n'initialise même pas ma fonction rand : je me fiche que le nuage de point quand on perd soit le même à chaque fois qu'on relance le jeu

Ajouté le 03/03/2014 à 10:43 :
Quant aux autres jeux, je prenais effectivement le nombre de frames écoulées depuis le lancement, histoire de pas m'embêter avec le RTC.
Totoyo Hors ligne Membre d'honneur Points: 16103 Défis: 102 Message

Citer : Posté le 15/03/2014 10:16 | #


J'ai une question très bête, mais google n'a pas été un bon ami...
Comment fait-on pour récupérer la bibliothèque stdlib.h ?
Lephenixnoir En ligne Administrateur Points: 24706 Défis: 170 Message

Citer : Posté le 15/03/2014 10:21 | #


Tu parles du header ou de la lib elle-même ?
Le header se trouve simplement dans le dossier C:\Program Files\CASIO\fx-9860G SDK\OS\SH\include (par défaut).

Par contre, j'ai peur que la bibliothèque standard (.a) ne soit intégrée au système, puisqu'il n'y a pas besoin de la lier.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Totoyo Hors ligne Membre d'honneur Points: 16103 Défis: 102 Message
Lephenixnoir En ligne Administrateur Points: 24706 Défis: 170 Message

Citer : Posté le 27/06/2014 18:45 | #


Je viens de voir un truc :
C'est bien joli, mais rand() ne retourne qu'un nombre compris entre 0 et 2^32-1 = 4294967295.

rand() renvoie un int, donc entre -2^31 = -2'147'483'648 et 2^31-1 = 2'147'483'647.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 27/06/2014 18:57 | #


Ou un unsigned int donc entre 0 et 4'294'967'295
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lephenixnoir En ligne Administrateur Points: 24706 Défis: 170 Message

Citer : Posté le 27/06/2014 18:58 | #


C++ Reference a écrit :
int rand (void);

Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Positon Hors ligne Rédacteur Points: 2396 Défis: 57 Message

Citer : Posté le 27/06/2014 18:59 | #


Oui mais dans le prototype de la fonction on voit bien que c'est un int non signé qui est retourné.
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 27/06/2014 19:01 | #


Si ça te perturbe tant que ça, t'as qu'à modifier le topic
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lephenixnoir En ligne Administrateur Points: 24706 Défis: 170 Message

Citer : Posté le 27/06/2014 19:02 | #


Quel prototype ?
Je suis désolé, si c'est un int il est forcément signé.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 27/06/2014 19:03 | #


Enfin, rand()%5 ≥ 0
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Theprog Hors ligne Membre Points: 1447 Défis: 20 Message

Citer : Posté le 05/08/2014 22:42 | #


Bon juste histoire d'etre sur,
J'ai souvent lorsque j'initialise avec srand() lorsque l'add-in se ferme un plantage de l’émulateur. En fait si je veux par exemple ouvrir une des fonctions de base de la calto (par exemple RunM) il me sort une jolie fenêtre pop-up de son grand chapeau avec:
Execution has stopped due to an error!
Noexisting data memory at blablabla

C'est a cause de la fonction et de ce SDK de ***** ou c'est de ma faute ?

Edit: En fait ça me le fait pas forcement avec cette fonction mais avec une grandes majorités des fonctions
Darkysun Hors ligne Membre Points: 1747 Défis: 52 Message

Citer : Posté le 05/08/2014 23:08 | #


Tu ne peux pas ouvrir RunMat sur l'émulateur cela n'a absolument aucun rapport avec ta fonction
Si je ne réponds pas à un post depuis trop longtemps : envoyez-moi un message pour me le rappeler !




Theprog Hors ligne Membre Points: 1447 Défis: 20 Message

Citer : Posté le 05/08/2014 23:12 | #


Si je peux pas l'utiliser mais normalement tu peux tomber sur une fenetre "Not availible" (ou presque ) mais qui ne stoppe pas l'emulation, c'est interne a la calto alors que la ca coupe tout et ca me met ca dans une pop up windows
Darkysun Hors ligne Membre Points: 1747 Défis: 52 Message

Citer : Posté le 05/08/2014 23:14 | #


a ca fait pop-up windows dsl j'avais pas compris
Tu devrais nous donner ta fonction pour voir se qui va pas
Si je ne réponds pas à un post depuis trop longtemps : envoyez-moi un message pour me le rappeler !




Lephenixnoir En ligne Administrateur Points: 24706 Défis: 170 Message

Citer : Posté le 10/08/2014 22:35 | #


C'est un bug assez récurrent qui peut se produire pour toute une infinité de raisons... déjà, évite de quitter l'application avec IsKeyDown(), je crois que ça pose déjà problème.
Après, ce bug je ne le rencontre quasiment jamais, alors je peux pas trop te dire... il semble que ce soit dû à un programme arrêté de manière un peu barbare (sans désallouer, ou sortir des boucles)...
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Theprog Hors ligne Membre Points: 1447 Défis: 20 Message

Citer : Posté le 13/08/2014 15:25 | #


Ben en fait, c'est le srand () qui faisait planter fourmizzz.
Je sais pas si c'était du au RTC cet ticks mais ça m'étonne vu que je l'utilisait dans d'autres jeux de la même manière sans que ça pose de soucis...
Lephenixnoir En ligne Administrateur Points: 24706 Défis: 170 Message

Citer : Posté le 13/08/2014 16:12 | #


Ben, c'est sans doute pas srand() vu qu'elle fait qu'initialiser une variable... c'est beaucoup plus probablement RTC_getTicks(), mais j'ai rencontré ce bug bien avant d'utiliser cette fonction.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Theprog Hors ligne Membre Points: 1447 Défis: 20 Message

Citer : Posté le 14/08/2014 18:51 | #


OK merci
-florian66- Hors ligne Ancien rédacteur Points: 2384 Défis: 20 Message

Citer : Posté le 30/09/2014 19:52 | #


j'ai une erreur "sytem error" Target E6FF2136" et j'ai une calto graph 35+ tweaké graph 75 est ce compatible SH4 ? et ça marche sur l'émulateur


Ajouté le 30/09/2014 à 20:00 :
pb résolu c'etait srand(....); qui ne marchais pas
In Arch, I trust ! And you ?
Legolas Hors ligne Ancien rédacteur Points: 3266 Défis: 104 Message

Citer : Posté le 17/06/2015 11:39 | #


Merci pour le tutoriel Dark Storm ! /D

Toutefois, sauriez-vous pourquoi j'ai exactement la même erreur qu'une incompatibilité SH4 sur l'émulateur du SDK officiel avec ce petit code :

[brown]#include [gray]"fxlib.h"[/gray][/brown]
[brown]#include [gray]"stdlib.h"[/gray][/brown]

static [purple]int[/purple] SysCallCode[] = {[maroon]0[/maroon]xD201422B,[maroon]0[/maroon]x60F20000,[maroon]0[/maroon]x80010070};
static [purple]int[/purple] (*SysCall)(int R4, [purple]int[/purple] R5, [purple]int[/purple] R6, [purple]int[/purple] R7, [purple]int[/purple] FNo ) = (void*)&SysCallCode;

[purple]int[/purple] AddIn_main(int isAppli, unsigned short OptionNum)
{
    [purple]unsigned int[/purple] key;
    [purple]unsigned char[/purple] *pic;
    [purple]int[/purple] d=[maroon]0[/maroon];
    [purple]int[/purple] i=[maroon]1[/maroon];
    [purple]int[/purple] x, y, l, v;

    [b][blue]for[/blue][/b] (i; i<100000; i++)
    {
        x = RanFloat(0, [maroon]1[/maroon]);
        y = RanFloat(0, [maroon]1[/maroon]);
        l = x*x+y*y;
        
        [b][blue]if[/blue][/b] (l<1)
        {
            d++;
        }

        v = [maroon]4[/maroon]*d/i;

        sprintf(pic,(const unsigned char*)[gray]"%d"[/gray],v);
        PrintMini(30, [maroon]30[/maroon], (unsigned [purple]char[/purple] *)pic, [maroon]1[/maroon]);

        Bdisp_AllClr_DDVRAM();
    }
    

    [b][blue]while[/blue][/b](1){
        GetKey(&key);
    }

    [b][blue]return[/blue][/b] 1;
}

[purple]int[/purple] RTC_getTicks()
{
     [b][blue]return[/blue][/b] (*SysCall)(0, [maroon]0[/maroon], [maroon]0[/maroon], [maroon]0[/maroon], [maroon]0[/maroon]x3B);
}

RanFloat(float min, [purple]float[/purple] max)
{
    [b][blue]return[/blue][/b] ( rand() / RAND_MAX ) * (max - min) + min;
}

[brown]#pragma section _BR_Size[/brown]
unsigned long BR_Size;
[brown]#pragma section[/brown]


[brown]#pragma section _TOP[/brown]

[purple]int[/purple] InitializeSystem(int isAppli, unsigned short OptionNum)
{
    [b][blue]return[/blue][/b] INIT_ADDIN_APPLICATION(isAppli, OptionNum);
}

#pragma section

Mes programmes
Cacher les programmes
Mes défis
Cacher les défis




LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 32 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd